<?php


namespace app\common;
use Elliptic\EC;
use kornrunner\Keccak;
use app\common\service\CaptchaService;

trait RootEncrypt
{
    /**
     * 后台加密秘钥
     * @var string
     */
    private $encryptKey = 'd680f2a3275537157ee915c615788913';

    /**
     * API接口加密秘钥
     * @var string
     */
    private $apiEncryptKey = '755b90e398983818f79f749583592573';

    /**
     * 登录密码加密
     * @param string $password
     * @return string
     */
    public function encAdminPwd(string $password)
    {
        return md5(md5($password) . $this->encryptKey);
    }

    /**
     * 根据公钥生成地址
     * @param $pubkey
     * @return string
     * @throws \Exception
     */
    public function pubKeyToAddress($pubkey) {
        return "0x" . substr(Keccak::hash(substr(hex2bin($pubkey->encode("hex")), 1), 256), 24);
    }

    /**
     * 登录签名校验
     * @param $message
     * @param $signature
     * @param $address
     * @return bool
     * @throws \Exception
     */
    public function verifySignature($message, $signature, $address) {
        $msglen = strlen($message);
        $hash   = Keccak::hash("\x19Ethereum Signed Message:\n{$msglen}{$message}", 256);
        $sign   = ["r" => substr($signature, 2, 64),
            "s" => substr($signature, 66, 64)];
        $recid  = ord(hex2bin(substr($signature, 130, 2))) - 27;
        if ($recid != ($recid & 1)) {
            return false;
        }
        $ec = new EC('secp256k1');
        $pubkey = $ec->recoverPubKey($hash, $sign, $recid);
        return strtolower($address) == strtolower($this->pubKeyToAddress($pubkey));
    }

    /**
     * 图形验证码校验
     * @param string $code 图形验证码
     * @param string $key 验证因子
     * @param bool $cast 是否抛出异常
     * @return bool
     * @throws RootException
     */
    public function checkImgCode(string $code, string $key, bool $cast = flase)
    {
        // 校验结果
        $checkResult = (new CaptchaService())->verifyImg($code, $key);
        if ($cast && !$checkResult) {
            throw new RootException('图形验证码校验失败');
        }
        return $checkResult;
    }

    /**
     * API密码校验
     * @param string $address 钱包地址
     * @param string $password
     * @return bool
     */
    public function checkApiPwd(string $address, string $password)
    {
        return $this->generateApiPwd($address)  == $password;
    }

    /**
     * 生成密码
     * @param string $address 钱包地址
     * @return string
     */
    public function generateApiPwd(string $address)
    {
        return md5(substr($address, 7, 25) . $this->apiEncryptKey);
    }

    /**
     * 登录密码校验
     * @param string $password
     * @param string $encPassword
     * @return bool
     */
    protected function checkAdminPwd(string $password, string $encPassword)
    {
        return $this->encAdminPwd($password) == $encPassword;
    }
}